package com.nervenets.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCommands;

import java.lang.reflect.Method;

@Aspect
@Component
public class RedisLockerAspect {
    @Autowired
    JedisCommands jedisCluster;

    @Pointcut("@annotation(com.nervenets.aspect.RedisLocker)")
    public void controllerAspect() {
    }

    @Around("controllerAspect()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        RedisLocker locker = getLockKey(pjp);
        String lockKey = locker.lockKey();
        boolean hasLocked = jedisCluster.setnx(lockKey, lockKey) == 1;
        if (hasLocked) {
            try {
                jedisCluster.expire(lockKey, locker.holdTime());
                pjp.proceed();
                //jedisCluster.del(lockKey);//必有过期时间，不作删除操作
            } catch (Exception ex) {
                ex.printStackTrace();
                //jedisCluster.del(lockKey);
                throw ex;
            }
        }

    }

    public RedisLocker getLockKey(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        RedisLocker rtnValue = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    rtnValue = method.getAnnotation(RedisLocker.class);
                    break;
                }
            }
        }
        return rtnValue;
    }

}
